package city.spring.modules.expense.controller;

import city.spring.modules.cardinfo.entity.CardNumberEntity;
import city.spring.modules.cardinfo.service.CardNumberService;
import city.spring.modules.cardinfo.vo.CardNumberEntityVO;
import city.spring.modules.expense.entity.ExpenseRecordEntity;
import city.spring.modules.expense.service.ExpenseRecordService;
import city.spring.modules.expense.vo.ExpenseRecordEntityVO;
import city.spring.utils.MyBatisUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import lombok.NonNull;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Controller：费用记录（缴费/消费）
 *
 * @author pxm
 * @date 2020-08-25 15:19:20
 */
@RestController
@RequestMapping("/expense_record")
public class ExpenseRecordController extends ApiController {
    private final ExpenseRecordService expenseRecordService;
    private final CardNumberService cardNumberService;
    /**
     * 实体类可排序字段
     */
    private final List<SFunction<ExpenseRecordEntity, ?>> entityOrderFields;

    public ExpenseRecordController(ExpenseRecordService expenseRecordService, CardNumberService cardNumberService) {
        this.expenseRecordService = expenseRecordService;
        this.cardNumberService = cardNumberService;
        entityOrderFields = new ArrayList<>();
        entityOrderFields.add(ExpenseRecordEntity::getId);
        entityOrderFields.add(ExpenseRecordEntity::getOldmanId);
        entityOrderFields.add(ExpenseRecordEntity::getProjectId);
        entityOrderFields.add(ExpenseRecordEntity::getBedNum);
        entityOrderFields.add(ExpenseRecordEntity::getMoney);
        entityOrderFields.add(ExpenseRecordEntity::getHappenTime);
        entityOrderFields.add(ExpenseRecordEntity::getPayer);
        entityOrderFields.add(ExpenseRecordEntity::getType);
        entityOrderFields.add(ExpenseRecordEntity::getCategory);
        entityOrderFields.add(ExpenseRecordEntity::getPayType);
        entityOrderFields.add(ExpenseRecordEntity::getRegistrant);
        entityOrderFields.add(ExpenseRecordEntity::getInvalidTime);
        entityOrderFields.add(ExpenseRecordEntity::getIsInvalid);
        entityOrderFields.add(ExpenseRecordEntity::getRemarks);
        entityOrderFields.add(ExpenseRecordEntity::getSettlementStatus);
        entityOrderFields.add(ExpenseRecordEntity::getStatus);
        entityOrderFields.add(ExpenseRecordEntity::getGmtCreate);
        entityOrderFields.add(ExpenseRecordEntity::getGmtModified);
    }

    /**
     * 预存款充值 增加预存缴费记录，更新卡片信息的余额
     *
     * @param entity
     * @return
     */
    @PostMapping("depositAdd")
    public Object depositAdd(@RequestBody ExpenseRecordEntity entity, @NonNull Principal user) {
        expenseRecordService.saveDepositRecord(entity, user);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 一卡通余额充值  增加预存缴费记录，更新卡片信息的余额
     *
     * @param entity
     * @return
     */
    @PostMapping("cardBalanceAdd")
    public Object cardBalanceAdd(@RequestBody ExpenseRecordEntity entity, @NonNull Principal user) {
        expenseRecordService.saveCardBalanceRecord(entity, user);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 其他消费  增加消费记录（增值消费项，来自收费项目管理的收费项目）
     *
     * @param entity
     * @return
     */
    @PostMapping("otherConsumptionAdd")
    public Object otherConsumptionAdd(@RequestBody ExpenseRecordEntity entity, @NonNull Principal user) {
        expenseRecordService.saveOtherConsumptionRecord(entity, user);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 水电消费  增加水电消费记录
     *
     * @param entity
     * @return
     */
    @PostMapping("waterOrElectricAdd")
    public Object waterOrElectricAdd(@RequestBody ExpenseRecordEntity entity, @NonNull Principal user) {
        expenseRecordService.saveWaterOrElectricRecord(entity, user);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 分页获取 <strong>预存缴费记录</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping("depositList")
    public Object depositList(@PageableDefault @SortDefault(sort = "happen_time", direction = Sort.Direction.DESC) Pageable pageable, ExpenseRecordEntityVO entity) {
        QueryWrapper<? extends ExpenseRecordEntity> queryWrapper = buildQuery(entity);
        return success(expenseRecordService.depositListPage(MyBatisUtils.toPage(pageable), queryWrapper));
    }

    /**
     * 分页获取 <strong>某个老人的预存/消费（或用预存抵扣其他交费）记录</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping("someoneDepositList/{cardId}")
    public Object someoneDepositList(@PageableDefault Pageable pageable, ExpenseRecordEntityVO entity, @PathVariable String cardId) {
        QueryWrapper<? extends ExpenseRecordEntity> queryWrapper = buildQuery(entity);
        CardNumberEntity cardNumberEntity = cardNumberService.getById(cardId); // 根据卡片ID 查找该卡片记录，获得人员ID
        String personId = cardNumberEntity.getPerson();
        queryWrapper.eq("t1.oldman_id", personId); // 查询该人员的预存缴费记录
        queryWrapper.like("t1.category", "预存"); // 费用记录里类别为预存交费的记录
        return success(expenseRecordService.depositListPage(MyBatisUtils.toPage(pageable), queryWrapper));
    }

    /**
     * 分页获取 <strong>某个老人的一卡通余额充值/消费记录</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping("someoneCardDepositList/{cardId}")
    public Object someoneCardDepositList(@PageableDefault Pageable pageable, ExpenseRecordEntityVO entity, @PathVariable String cardId) {
        QueryWrapper<? extends ExpenseRecordEntity> queryWrapper = buildQuery(entity);
        CardNumberEntity cardNumberEntity = cardNumberService.getById(cardId); // 根据卡片ID 查找该卡片记录，获得人员ID
        String personId = cardNumberEntity.getPerson();
        queryWrapper.eq("t1.oldman_id", personId); // 查询该人员的记录
        queryWrapper.eq("t1.category", "一卡通"); // 费用记录里类别为一卡通的记录
        return success(expenseRecordService.depositListPage(MyBatisUtils.toPage(pageable), queryWrapper));
    }

    /**
     * 分页获取 <strong>其他消费 消费记录</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping("otherConsumptionRecordList")
    public Object otherConsumptionRecordList(@PageableDefault Pageable pageable, ExpenseRecordEntityVO entity) {
        QueryWrapper<? extends ExpenseRecordEntity> queryWrapper = buildQuery(entity);
        queryWrapper.eq("t1.category", "其他消费"); // 查询该人员的预存缴费记录
        return success(expenseRecordService.depositListPage(MyBatisUtils.toPage(pageable), queryWrapper));
    }

    /**
     * 分页获取 <strong>水电 消费记录</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping("waterOrElectricRecordList")
    public Object waterOrElectricRecordList(@PageableDefault Pageable pageable, ExpenseRecordEntityVO entity) {
        QueryWrapper<? extends ExpenseRecordEntity> queryWrapper = buildQuery(entity);
        queryWrapper.eq("t1.category", "水电消费"); // 查询该人员的预存缴费记录
        return success(expenseRecordService.depositListPage(MyBatisUtils.toPage(pageable), queryWrapper));
    }

    /**
     * 根据老人ID获取卡片信息：预存款余额、一卡通余额、卡号等
     */
    @GetMapping("getCardInfoByPersonId/{personId}")
    public Object getCardInfoByPersonId(@PathVariable String personId) {
        CardNumberEntityVO cardNumberEntityVO = cardNumberService.getByPersonId(personId);
        return success(cardNumberEntityVO);
    }

    /**
     * 获取全部的 <strong>费用记录（缴费/消费）</strong> 列表
     */
    @GetMapping("all")
    public Object listAll(@PageableDefault Pageable pageable, ExpenseRecordEntity entity) {
        LambdaQueryChainWrapper<ExpenseRecordEntity> lambdaQuery = buildLambdaQuery(entity);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        return success(lambdaQuery.list());
    }


    /**
     * 获取一个 <strong>费用记录（缴费/消费）</strong>
     *
     * @param id 主键ID
     */
    @GetMapping("{id}")
    public Object info(@PathVariable String id) {
        return success(expenseRecordService.getById(id));
    }

    /**
     * 根据老人ID获取最新的结算记录，用于结算审核
     * @param oldmanId
     * @return
     */
//    @GetMapping("settlement/getLatestRecord/{oldmanId}")
//    public Object getLatestSettlementRecord(@PathVariable String oldmanId) {
//        return success(expenseRecordService.getLatestSettlementRecord(oldmanId));
//    }

    /**
     * 根据费用ID获取最新的结算记录，用于结算审核
     *
     * @param id
     * @return
     */
    @GetMapping("settlement/getLatestRecord/{id}")
    public Object getSettlementRecord(@PathVariable String id) {
        return success(expenseRecordService.getSettlementRecord(id));
    }

    /**
     * 添加一个 <strong>费用记录（缴费/消费）</strong>
     *
     * @param entity 修改后的信息
     */
    @PostMapping
    public Object add(@RequestBody ExpenseRecordEntity entity) {
        expenseRecordService.saveExpenseRecord(entity);

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }


    /**
     * 修改一个 <strong>费用记录（缴费/消费）</strong>
     *
     * @param id     主键ID
     * @param entity 修改后的信息
     */
    @PutMapping("{id}")
    public Object update(@PathVariable String id, @RequestBody ExpenseRecordEntity entity) {
        entity.setId(id);
        expenseRecordService.updateExpenseRecord(entity);
        return new ResponseEntity<>(HttpStatus.OK);
    }


    /**
     * 审核结算
     *
     * @param id
     * @param entity
     * @param user
     * @return
     */
    @PutMapping("checkSettlement/{id}")
    public Object checkSettlement(@PathVariable String id, @RequestBody ExpenseRecordEntity entity, @NonNull Principal user) {
        entity.setId(id);
        expenseRecordService.checkSettlement(entity, user);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 删除一个 <strong>费用记录（缴费/消费）</strong>
     *
     * @param id 主键ID
     */
    @DeleteMapping("{id}")
    public Object delete(@PathVariable String id) {
        expenseRecordService.deleteExpenseRecord(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    /**
     * 删除多个 <strong>费用记录（缴费/消费）</strong>
     *
     * @param ids 主键ID列表
     */
    @DeleteMapping
    public Object deleteIds(@RequestBody List<String> ids) {
        expenseRecordService.deleteExpenseRecord(ids);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    /**
     * 构建查询条件内容
     *
     * @param entity 实体对象
     * @return lambda query chain wrapper
     */
    private LambdaQueryChainWrapper<ExpenseRecordEntity> buildLambdaQuery(ExpenseRecordEntity entity) {
        LambdaQueryChainWrapper<ExpenseRecordEntity> lambdaQuery = expenseRecordService.lambdaQuery();
        lambdaQuery.eq(StringUtils.isNotBlank(entity.getId()), ExpenseRecordEntity::getId, entity.getId());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getOldmanId()), ExpenseRecordEntity::getOldmanId, entity.getOldmanId());
        lambdaQuery.eq(entity.getMoney() != null, ExpenseRecordEntity::getMoney, entity.getMoney());
        lambdaQuery.eq(entity.getHappenTime() != null, ExpenseRecordEntity::getHappenTime, entity.getHappenTime());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getPayer()), ExpenseRecordEntity::getPayer, entity.getPayer());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getType()), ExpenseRecordEntity::getType, entity.getType());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getCategory()), ExpenseRecordEntity::getCategory, entity.getCategory());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getPayType()), ExpenseRecordEntity::getPayType, entity.getPayType());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getRegistrant()), ExpenseRecordEntity::getRegistrant, entity.getRegistrant());
        lambdaQuery.eq(entity.getInvalidTime() != null, ExpenseRecordEntity::getInvalidTime, entity.getInvalidTime());
        lambdaQuery.eq(entity.getIsInvalid() != null, ExpenseRecordEntity::getIsInvalid, entity.getIsInvalid());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getRemarks()), ExpenseRecordEntity::getRemarks, entity.getRemarks());
        lambdaQuery.eq(entity.getSettlementStatus() != null, ExpenseRecordEntity::getSettlementStatus, entity.getSettlementStatus());
        lambdaQuery.eq(entity.getStatus() != null, ExpenseRecordEntity::getStatus, entity.getStatus());
        lambdaQuery.eq(entity.getGmtCreate() != null, ExpenseRecordEntity::getGmtCreate, entity.getGmtCreate());
        lambdaQuery.eq(entity.getGmtModified() != null, ExpenseRecordEntity::getGmtModified, entity.getGmtModified());
        return lambdaQuery;
    }

    /**
     * 构建查询条件内容
     *
     * @param entity 实体对象
     * @return lambda query chain wrapper
     */
    private QueryWrapper<? extends ExpenseRecordEntity> buildQuery(ExpenseRecordEntityVO entity) {
        QueryWrapper<? extends ExpenseRecordEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(entity.getId()), "t1.id", entity.getId());
        wrapper.like(StringUtils.isNotBlank(entity.getOldmanId()), "t1.oldman_id", entity.getOldmanId());
        wrapper.like(StringUtils.isNotBlank(entity.getProjectId()), "t1.project_id", entity.getProjectId());
        wrapper.like(StringUtils.isNotBlank(entity.getProjectName()), "t4.name", entity.getProjectName());
        wrapper.like(StringUtils.isNotBlank(entity.getBedNum()), "t1.bed_num", entity.getBedNum());
        wrapper.like(StringUtils.isNotBlank(entity.getOldmanName()), "t2.oldman_name", entity.getOldmanName());
        wrapper.eq(entity.getMoney() != null, "t1.money", entity.getMoney());
        wrapper.eq(entity.getHappenTime() != null, "t1.happen_time", entity.getHappenTime());
        wrapper.like(StringUtils.isNotBlank(entity.getPayer()), "t1.payer", entity.getPayer());
        wrapper.like(StringUtils.isNotBlank(entity.getType()), "t1.type", entity.getType());
        wrapper.like(StringUtils.isNotBlank(entity.getCategory()), "t1.category", entity.getCategory());
        wrapper.like(StringUtils.isNotBlank(entity.getPayType()), "t1.pay_type", entity.getPayType());
        wrapper.like(StringUtils.isNotBlank(entity.getRegistrant()), "t1.registrant", entity.getRegistrant());
        wrapper.like(StringUtils.isNotBlank(entity.getRegistrantName()), "t3.username", entity.getRegistrantName());
        wrapper.eq(entity.getInvalidTime() != null, "t1.invalid_time", entity.getInvalidTime());
        wrapper.eq(entity.getIsInvalid() != null, "t1.is_invalid", entity.getIsInvalid());
        wrapper.like(StringUtils.isNotBlank(entity.getRemarks()), "t1.remarks", entity.getRemarks());
        wrapper.eq(entity.getSettlementStatus() != null, "t1.settlement_status", entity.getSettlementStatus());
        wrapper.eq(entity.getGmtCreate() != null, "t1.gmt_create", entity.getGmtCreate());
        wrapper.eq(entity.getStatus() != null, "t1.status", entity.getStatus());
        wrapper.eq(entity.getGmtModified() != null, "t1.gmt_modified", entity.getGmtModified());
        return wrapper;
    }

    /**
     * 构建结算记录 查询条件内容
     *
     * @param entity 实体对象
     * @return lambda query chain wrapper
     */
    private QueryWrapper<? extends ExpenseRecordEntity> buildQuery2(ExpenseRecordEntityVO entity) {
        QueryWrapper<? extends ExpenseRecordEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(entity.getId()), "t1.id", entity.getId());
        wrapper.like(StringUtils.isNotBlank(entity.getOldmanId()), "t1.oldman_id", entity.getOldmanId());
        wrapper.like(StringUtils.isNotBlank(entity.getOldmanName()), "t2.oldman_name", entity.getOldmanName());
        wrapper.eq(entity.getHappenTime() != null, "t1.happen_time", entity.getHappenTime());
        wrapper.like(StringUtils.isNotBlank(entity.getType()), "t1.type", entity.getType());
        wrapper.like(StringUtils.isNotBlank(entity.getCategory()), "t1.category", entity.getCategory());
        wrapper.like(StringUtils.isNotBlank(entity.getRegistrant()), "t1.registrant", entity.getRegistrant());
        wrapper.like(StringUtils.isNotBlank(entity.getCheckerName()), "t4.username", entity.getCheckerName());
        wrapper.like(StringUtils.isNotBlank(entity.getRegistrantName()), "t3.username", entity.getRegistrantName());
        wrapper.eq(entity.getSettlementStatus() != null, "t1.settlement_status", entity.getSettlementStatus());
        wrapper.eq(entity.getStatus() != null, "t1.status", entity.getStatus());
        return wrapper;
    }

    /**
     * 保存入院缴费 生成缴费记录
     *
     * @param entity
     * @return
     */
    @PostMapping("saveCheckinFee")
    public Object saveCheckinFee(@RequestBody ExpenseRecordEntity entity) {
        expenseRecordService.saveCheckinFee(entity);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 保存月度缴费 生成缴费记录
     *
     * @param entity
     * @return
     */
    @PostMapping("saveMonthFee")
    public Object saveMonthFee(@RequestBody ExpenseRecordEntity entity) {
        expenseRecordService.saveMonthFee(entity);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 获取 某个老人的月度缴费记录 List
     *
     * @param personId
     * @return
     */
    public Object getOnesMonthPayRecords(@PathVariable String personId) {
        return success(expenseRecordService.getOnesMonthPayRecords(personId));
    }

    /**
     * 退住結算
     *
     * @param entity
     * @return
     */
    @PostMapping("leaveSettlement/{leaveDate}/{monthEnd}/{invalidState}")
    public Object leaveSettlement(@RequestBody ExpenseRecordEntity entity, @PathVariable Date leaveDate, @PathVariable Date monthEnd, @PathVariable Integer invalidState) {
        expenseRecordService.saveLeaveSettlement(entity, leaveDate, monthEnd, invalidState);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }


    /**
     * 分页获取 <strong>退住结算记录</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping("settlementRecords")
    public Object settlementRecords(@PageableDefault @SortDefault(sort = "t1.happen_time", direction = Sort.Direction.DESC) Pageable pageable, ExpenseRecordEntityVO entity) {
        QueryWrapper<? extends ExpenseRecordEntity> queryWrapper = buildQuery(entity);
        queryWrapper.eq("t1.category", "退住结算");
        return success(expenseRecordService.getSettlementRecords(MyBatisUtils.toPage(pageable), queryWrapper));
    }

    /**
     * 结算账单：应交账单 根据结算记录Id，对应的老人id，获取入住记录中老人最新的的入住日期、退住日期，再从缴费明细记录获取这两个日期间的明细记录。
     *
     * @param expecseId
     * @return
     */
    @GetMapping("billDetails/{expecseId}")
    public Object getBillDetailsBetween2Date(@PathVariable String expecseId) {
        return success(expenseRecordService.getBillDetailsBetween2Date(expecseId));
    }

    /**
     * 单据打印：老人最新的入住记录的入住日期、退住日期，再从缴费明细记录获取这两个日期间的明细记录。
     *
     * @param expenseId
     * @return
     */
    @GetMapping("billPrintDetail/{expenseId}")
    public Object getBillPrintDetail(@PathVariable String expenseId) {
        return success(expenseRecordService.getBillPrintDetail(expenseId));
    }

    /**
     * 结算打印：获取长者信息和结算信息
     *
     * @param expenseId
     * @return
     */
    @GetMapping("settlementprintInfo/{expenseId}")
    public Object getSettlementPrintInfo(@PathVariable String expenseId) {
        return success(expenseRecordService.getSettlementPrintInfo(expenseId));
    }
}
